
/**
*tagfolder
*Licensed under LGPL
*http://code.google.com/p/tagfolder
*chuanshenglu@gmail.com
*xrjieyee@gmail.com
*
*/

#ifndef __TF_SERVER_BUFFER_H__
#define __TF_SERVER_BUFFER_H__

#include <string>
#include <map>
#include <set>
#include <fstream>

//============================================
//Abstract class to do server buffering ;
//============================================
/**
 *Abstract interface to all buffers;
 */
template< typename IDType, typename DataType >
class TFBuffer
{
public:
	TFBuffer ( std::string& dbfile ) {}
	TFBuffer ( TFBuffer & ) {}
	virtual ~TFBuffer ( ) = 0;
	virtual void ShrinkBuffer ( ) = 0;
	virtual DataType GetById ( IDType id) = 0;
	virtual bool RemoveById ( IDType id ) = 0;
        virtual bool Add( DataType& obj ) = 0;
        virtual bool GetNextId() = 0;
	virtual long Size() = 0;
};
/**
 *TFServerBuffer:
 *
 *
 */
template < typename IDType, typename DataType >
class TFServerBuffer
//        :public TFBuffer<IDType, DataType>
{
public:
        /**
         *Construct a TFServerBuffer object from a file;
         *the only construction approach;
         */
	TFServerBuffer ( std::string& dbfile ) 
                :idcount(0),
                opcount(0),
                dbfilename(dbfile)
        {
                LoadFromFile();
        }
        /**
         *Explicitly declare that do not copy construct!!!!
         */
	TFServerBuffer ( TFServerBuffer & ) { } 
        /**
         *Destructor
         */
	virtual ~TFServerBuffer ( )
        {
                WriteBack();
        }
	/**
	*Shrink buffer to proper size to ease memory burden;
	*/
	virtual void ShrinkBuffer ( )
        {
        }
	/**
	*Get object from the buffer with id;
	*/
	virtual DataType GetById ( IDType id)
        {
                DataType ret;
                std::map<IDType, DataType>::iterator itr = Buffer.find(id);
                if( itr != Buffer.end() )
                {
                        return itr->second;
                }
                return ret;
        }
	/**
	 *Remove object by id;
	 */
	virtual bool RemoveById ( IDType id )
        {
                std::map<IDType, DataType>::iterator itr = Buffer.find(id);
                if( itr != Buffer.end() )
                {
                        Buffer.erase( itr );
                        return true;
                }
                idcount++;
                opcount++;
                return false;
        }
        /**
         *Add object to the buffer;
         */
        virtual bool Add( DataType& obj )
        {
                Buffer.insert( std::pair<IDType, DataType>( GetNextId(), obj));
                return true;
        }
        /**
         *Get next unused id;
         */
        virtual bool GetNextId()
        {
                return ++idcount;
        }
	/**
	 *How many objects was stored in this buffer;
	 */
	virtual long Size()
        {
                return Buffer.size();
        }
protected:
        /**
         *Write data back to file;
         */
        virtual bool WriteBack( )
        {
                if( dbfilename == "" )
                {
                        return false;
                }
                std::ofstream tfout;
                tfout.open( dbfilename.c_str(),
                            std::ofstream::binary | std::ofstream::out );
                for(std::map<IDType, DataType>::iterator itr = Buffer.begin();
                    itr != Buffer.end();
                    itr++ )
                {
                        tfout <<itr->first <<itr->second <<std::endl;
                }
                tfout.close();
                return true;
        }
        /**
         *Load data from file to memory;
         */
        virtual bool LoadFromFile( )
        {
                if( dbfilename == "" )
                {
                        return false;
                }
                Buffer.clear();
                std::ifstream tfin;
                tfin.open( dbfilename.c_str(),
                          std::ifstream::binary | std::ifstream::in );
                while( tfin.good() )
                {
                        DataType data;
                        IDType id;
                        tfin >> id;
                        tfin >> data;
                        if( idcount < id)
                        {
                                idcount = id;
                        } 
                        Buffer.insert( std::pair<IDType, DataType>( id, data));
                }
                tfin.close();
                return true;
        }
protected:
        std::string dbfilename;
        std::map<IDType, DataType> Buffer;
        IDType idcount;
        long opcount;
};
/*
//==============================================
//Buffer to hold strings 
//==============================================
class TFStringBuffer
//: public TFServerBuffer < long, std::string >
{
 public:
	TFStringBuffer( std::string& );
	virtual ~TFStringBuffer ( );
 public:
	virtual void ShrinkBuffer ( );
	virtual long Size ( );
	virtual std::string GetById ( long );
	virtual std::string GetByIndex ( long );
	virtual bool RemoveById ( long );
	virtual bool RemoveByIndex ( long );
        virtual bool Add ( std::string& );
        virtual bool FindId( long id )
        {
          return ( Buffer.find(id) != Buffer.end() );
        }
        virtual long GetNextId()
        {
          return ++IdCount;
        }
        virtual long GetStringId( std::string& );
 protected:
        virtual bool WriteBack();
 protected:
	std::map< long , std::string > Buffer;
	std::string dbfile;
 private:
        unsigned long OpCount;
        unsigned long IdCount;
};
*/
//define phantom types to be convineont;
typedef TFServerBuffer<long,std::string>  TFStringBuffer;
typedef TFServerBuffer<long,std::string>  TFTagBuffer;
typedef TFServerBuffer<long,std::string>  TFFileBuffer;
typedef TFServerBuffer<long,long>         TFLinkBuffer;


//================================================
//
//================================================
//singleton
class TFBufferManager
{
public:
	virtual ~TFBufferManager();
	//virtual TFBuffer& GetBuffer(const char*);
        virtual TFStringBuffer& GetStringBuffer(const char* str)
        {
                std::string s(str);
                return GetStringBuffer(s);
        }
        virtual TFLinkBuffer& GetLinkBuffer(const char* str)
        {
                std::string s(str);
                return GetLinkBuffer(s);
        }
	virtual TFStringBuffer& GetStringBuffer(std::string&);
        virtual TFLinkBuffer& GetLinkBuffer(std::string&);
	static TFBufferManager& GetInstance();
private:
	static TFBufferManager* instance;
	TFBufferManager();
	std::map<std::string,TFStringBuffer*> StringBuffers;
        std::map<std::string,TFLinkBuffer*> LinkBuffers;
private:
	std::set<std::string> LegalBufferNames;
};

#endif
